Skip to content

Fix ty invalid assignment - #15222

Merged
cclauss merged 8 commits into
TheAlgorithms:masterfrom
kadubhumika:fix-ty-invalid-assignment
Sep 8, 2026
Merged

Fix ty invalid assignment#15222
cclauss merged 8 commits into
TheAlgorithms:masterfrom
kadubhumika:fix-ty-invalid-assignment

Conversation

@kadubhumika

Copy link
Copy Markdown
Contributor

Describe your change:

Fixed remaining ty invalid-assignment and related type-checking diagnostics across multiple existing files.

Changes include:

  • Fixed type annotations and optional value handling.
  • Added necessary assertions for image pixel access.
  • Fixed typing issues in linked lists, segment trees, heaps, automatic differentiation, and minimum cut implementations.
  • Explicitly imported urllib.request.
  • Fixed the CPU scheduling selection type-checking issue.
  • Updated DIRECTORY.md.

Validation performed:

ty check --exclude-scripts
All checks passed!



### Checklist:
* [ ] Add an algorithm?
* [x] Fix a bug or typo in an existing algorithm?
* [ ] Add or change doctests? -- Note: Please avoid changing both code and tests in a single pull request.
* [x] Documentation change?
* [x] I have read [CONTRIBUTING.md](https://github.com/TheAlgorithms/Python/blob/master/CONTRIBUTING.md).
* [x] This pull request is all my own work -- I have not plagiarized.
* [x] I know that pull requests will not be merged if they fail the automated tests.
* [ ] This PR only changes one algorithm file.  To ease review, please open separate PRs for separate algorithms.
* [x] All new Python files are placed inside an existing directory.
* [x] All filenames are in all lowercase characters with no spaces or dashes.
* [x] All functions and variable names follow Python naming conventions.
* [x] All function parameters and return values are annotated with Python [type hints](https://docs.python.org/3/library/typing.html).
* [ ] All functions have [doctests](https://docs.python.org/3/library/doctest.html) that pass the automated testing.
* [ ] All new algorithms include at least one URL that points to Wikipedia or another similar explanation.
* [ ] If this pull request resolves one or more open issues then the description above includes the issue number(s) with a [closing keyword](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue): "Fixes #ISSUE-NUMBER".

@algorithms-keeper algorithms-keeper Bot added awaiting reviews This PR is ready to be reviewed enhancement This PR modified some existing files tests are failing Do not merge until tests pass labels Sep 7, 2026
@github-actions
github-actions Bot force-pushed the fix-ty-invalid-assignment branch from df2fe0d to 2d7f5d2 Compare September 7, 2026 18:54
@algorithms-keeper algorithms-keeper Bot removed the tests are failing Do not merge until tests pass label Sep 7, 2026
@cclauss

cclauss commented Sep 8, 2026

Copy link
Copy Markdown
Member

@priya-sundaram-dev your review, please.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There’s a confirmed performance regression in minimum_cut.py and an assert in doubly_linked_list.py::delete() that changes empty-list behavior (and can be stripped under -O).

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR removes remaining ty invalid-assignment/type diagnostics by tightening typing and narrowing optional values across a set of existing algorithm implementations, and updates ty configuration to stop ignoring invalid-assignment.

Changes:

  • Removed ty’s rules.invalid-assignment = "ignore" so invalid assignments are surfaced instead of suppressed.
  • Added/adjusted type narrowing (e.g., assert ... is not None, cast(...), explicit optional handling) in several algorithms and data structures.
  • Cleaned up a few typing-related imports and assignments to satisfy stricter type checking.
File summaries
File Description
scheduling/cpuschedulingalgorithms.py Avoids indexing empty Treeview “values” when deleting a selected process.
pyproject.toml Stops ignoring ty’s invalid-assignment rule.
neural_network/input_data.py Adds explicit urllib.request import for type checking / usage clarity.
networking_flow/minimum_cut.py Replaces float("inf") with an integer upper bound for path_flow initialization (but currently adds avoidable per-iteration work).
machine_learning/automatic_differentiation.py Replaces defaultdict accumulation with a typed dict + explicit .get(...) defaults.
fractals/mandelbrot.py Adds a non-None assertion for PIL pixel access.
data_structures/linked_list/singly_linked_list.py Adds type annotation for head and asserts to narrow optionals during traversal.
data_structures/linked_list/doubly_linked_list.py Adds basic typing and asserts to narrow optionals (but introduces a new AssertionError path and redundancy).
data_structures/heap/binomial_heap.py Adds asserts to narrow internal optional heap pointers.
data_structures/binary_tree/non_recursive_segment_tree.py Uses cast(T, None) to satisfy typing for the pre-build segment tree array.
cellular_automata/one_dimensional.py Adds a non-None assertion for PIL pixel access.
cellular_automata/conways_game_of_life.py Adds a non-None assertion for PIL pixel access.
Review details

Suppressed comments (1)

data_structures/linked_list/doubly_linked_list.py:179

  • assert current is not None changes the empty-list behavior to raise AssertionError (and can be removed with python -O). Prefer an explicit check that raises the same ValueError used for “not found”, while still narrowing the type for current.data access.
    def delete(self, data) -> str:
        current = self.head
        assert current is not None

  • Files reviewed: 12/12 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 73 to 75
while bfs(residual, source, sink, parent):
path_flow = float("inf")
path_flow = max(max(row) for row in residual)
s = sink
Comment on lines +100 to 104
assert self.tail is not None
self.tail.next = new_node
assert self.tail is not None
new_node.previous = self.tail
self.tail = new_node

@priya-sundaram-dev priya-sundaram-dev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed all 12 files — this cleanly earns the removal of rules.invalid-assignment = "ignore" from pyproject.toml, and CI (ty/build/ruff) is green. Notes:

Correct and idiomatic

  • The Optional-narrowing assert ... is not None guards in the linked lists, heap, and img.load() sites (mandelbrot, conways_game_of_life, one_dimensional) are the right call for this repo's style.
  • non_recursive_segment_tree.py: cast(T, None) in place of the Any | T sentinel is a nice tightening.
  • singly_linked_list.delete_nth: binding delete_node = temp.next_node then temp.next_node = delete_node.next_node is equivalent to the old two-hop and reads better.
  • neural_network/input_data.py: adding import urllib.request is a real correctness fix — urllib.request was used but only urllib was imported (works only if another module happened to import the submodule first).
  • automatic_differentiation.py: swapping defaultdict(lambda: 0) for a typed dict + .get(param, np.zeros_like(...)) preserves the accumulation semantics (first hit: zeros_like + grad == grad) while giving ty a real value type.

The one behavioural line worth calling out for other reviewers — networking_flow/minimum_cut.py:

-        path_flow = float("inf")
+        path_flow = max(max(row) for row in residual)

This is correct: path_flow is only ever reduced via min(path_flow, residual[u][v]) down the augmenting path, so any value >= the path's bottleneck yields the identical result, and the global max residual capacity is always such an upper bound. It's also correctly placed inside the while bfs(...) loop rather than hoisted — reverse-edge residuals grow (residual[v][u] += path_flow) across augmentations, so a value computed once before the loop would not stay a valid upper bound. The tradeoff is O(V²) per augmentation; if you'd rather keep O(1) here, sys.maxsize (an int, so no assignment-type error) would also satisfy ty while matching the original intent exactly.

Tiny nit (non-blocking): in doubly_linked_list.insert_at_nth, the elif index == length branch asserts self.tail is not None twice with no reassignment between them — the second one is redundant and can be dropped.

Nothing blocking from me — looks good to merge.

@algorithms-keeper algorithms-keeper Bot removed the awaiting reviews This PR is ready to be reviewed label Sep 8, 2026
@cclauss
cclauss merged commit 636dd57 into TheAlgorithms:master Sep 8, 2026
6 checks passed

@priya-sundaram-dev priya-sundaram-dev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed — this is a clean, well-scoped pass and CI is green (build / ruff / ty / pre-commit all pass). The assert x is not None narrowing before mutating linked-list / heap / segment-tree nodes is the idiomatic way to satisfy ty here without changing runtime behavior, and dropping rules.invalid-assignment = "ignore" from pyproject.toml is the right end-state once the count hits zero. LGTM.

Two small things worth a note (non-blocking):

  • networking_flow/minimum_cut.py: path_flow = max(max(row) for row in residual) in place of float("inf") keeps path_flow an int (which is what silences ty), and it's still correct because the max residual capacity is an upper bound on every edge on the augmenting path, so the subsequent min(path_flow, residual[...][...]) still selects the true bottleneck. Since that equivalence isn't obvious to a future reader, a one-line # int upper bound on any single-edge capacity comment would help.
  • machine_learning/automatic_differentiation.py: swapping defaultdict(lambda: 0) for a plain dict + partial_deriv.get(param, np.zeros_like(dparam_dtarget)) is behavior-preserving (first-touch went from scalar 0 to a correctly-shaped zero array, which is actually slightly more correct for the +=). Good change.

No blockers from me.

@cclauss cclauss mentioned this pull request Sep 11, 2026
15 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement This PR modified some existing files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants